﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace OA.Common
{  /// <summary>
    /// Linq扩展公共方法
    /// </summary>
    public static class ExpressionExtensions
    {

        /*
        简单说就是这样，我们假定有两个函数：
            a => a < 10
            b => b > 0

            其中，a和b是
            expr1.Parameters[0]
            和
            expr2.Parameters[0]

            a < 10
            b > 0
            则是
            expr1.Body
            和
            expr2.Body


            所以，其实就是产生这样一个东西：
                 x =>  //x 就是 parameter = Expression.Parameter(typeof (T));
                x < 10 //第一个函数，用x替换了a
                &&     //AndAlso
                x > 0  //第二个函数，用x替换了b

            就是这个样子：
            x => x < 10 && x > 0

            所以简单说，就是把函数内联。

            作者：Ivony
            链接：https://www.zhihu.com/question/53671531/answer/136145313
            来源：知乎
            著作权归作者所有，转载请联系作者获得授权。
         
         */

        /// <summary>
        /// 替换表达式
        /// </summary>
        private class ReplaceExpressionVisitor : ExpressionVisitor
        {
            private readonly Expression _oldValue;
            private readonly Expression _newValue;

            public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
            {
                _oldValue = oldValue;
                _newValue = newValue;
            }

            public override Expression Visit(Expression node)
            {
                // 这里意味着什么？
                if (node == _oldValue)
                    return _newValue;
                return base.Visit(node);
            }
        }

        /// <summary>
        /// lamdba表达式拼接Add
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <param name="expr1">表达式1</param>
        /// <param name="expr2">表达式2</param>
        /// <returns>拼接后的表达式</returns>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            //获取T的参数
            var parameter = Expression.Parameter(typeof(T));

            //用T的参数去替换表达式的参数
            var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
            var left = leftVisitor.Visit(expr1.Body);

            var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
            var right = rightVisitor.Visit(expr2.Body);

            //重新拼接一个新的lambda表达式
            return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left, right), parameter);
        }


        /// <summary>
        /// lamdba表达式拼接Or
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <param name="expr1">表达式1</param>
        /// <param name="expr2">表达式2</param>
        /// <returns>拼接后的表达式</returns>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            //获取T的参数
            var parameter = Expression.Parameter(typeof(T));

            //用T的参数去替换表达式的参数
            var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
            var left = leftVisitor.Visit(expr1.Body);

            var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
            var right = rightVisitor.Visit(expr2.Body);

            //重新拼接一个新的lambda表达式
            return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
        }


    }

}
